package com.ft.oa.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ft.oa.domain.dto.ApiResult;
import com.ft.oa.domain.dto.sys.SecurityUser;
import com.ft.oa.domain.dto.condition.SysRoleDTO;
import com.ft.oa.domain.sys.*;
import com.ft.oa.mapper.sys.*;
import com.ft.oa.service.sys.SysRoleService;
import com.ft.oa.utils.SecurityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class SysRoleServiceImpl implements SysRoleService {

    @Resource
    private SysRoleMapper sysRoleMapper;
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private SysRoleAuthMapper sysRoleAuthMapper;
    @Resource
    private SysUserRoleMapper sysUserRoleMapper;
    @Resource
    private SysAuthMapper sysAuthMapper;

    @Override
    @Transactional
    public ApiResult add(SysRoleDTO role) {
        QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(SysRole::getDel, false)
                .eq(SysRole::getName, role.getName());
        List<SysRole> sysRoles = sysRoleMapper.selectList(wrapper);
        if(sysRoles.size()>0){
           return ApiResult.builder().code(40001).msg("角色名已经存在，请重新填写").build();
        }
        //新增角色
        SysRole saveRole = new SysRole(role);
        SecurityUser currentUser = SecurityUtils.getCurrentUser();
        saveRole.setCreator(currentUser.getId());
        saveRole.setCreateTime(LocalDateTime.now());
        sysRoleMapper.insert(saveRole);
        //角色添加权限
        updateRoleAuth(saveRole.getId(), role.getPermissions());
        return ApiResult.simpleSuccess();
    }

    @Override
    @Transactional
    public ApiResult edit(SysRoleDTO role) {
        QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(SysRole::getDel, false)
                .eq(SysRole::getName, role.getName());
        SysRole sysRole = sysRoleMapper.selectOne(wrapper);
        if( null!=sysRole &&  !role.getName().equals(sysRole.getName())){
            return ApiResult.builder().code(30001).msg("角色名不能重复，请重新填写").build();
        }
        SysRole save = new SysRole(role);
        save.setUpdateTime(LocalDateTime.now());
        sysRoleMapper.updateById(save);
        //角色添加权限
        updateRoleAuth(save.getId(), role.getPermissions());
        return ApiResult.simpleSuccess();
    }

    @Override
    @Transactional
    public void updateRoleAuth(Integer roleId, Set<Integer> permissions) {
        QueryWrapper<SysRoleAuth> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(SysRoleAuth::getRoleId, roleId);
        int delete = sysRoleAuthMapper.delete(wrapper);
        Set<Integer> pids = new HashSet<>();
        //传过来的只有子菜单的ID，递归添加父菜单ID，直到pid=0
        for (Integer permissionId : permissions) {
            pids = findPid(permissionId,pids);
        }
        pids.addAll(permissions);
        pids.stream()
                .map(permissionId -> new SysRoleAuth(roleId, permissionId))
                .forEach(e -> sysRoleAuthMapper.insert(e));
    }

    public Set<Integer> findPid(int permissionId,Set<Integer> pidSet){
        SysAuth sysAuth = sysAuthMapper.selectById(permissionId);
        if (sysAuth.getPid() == 0 ) {
            return pidSet;
        } else {
            pidSet.add(sysAuth.getPid());
            return findPid(sysAuth.getPid(),pidSet);
        }
    }




    @Override
    public List<SysRole> list() {
        QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(SysRole::getDel, false);
        List<SysRole> sysRoles = sysRoleMapper.selectList(wrapper);
        return sysRoles;
    }

    @Override
    public List<SysRole> userRoles(Long id) {
        QueryWrapper<SysUserRole> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(SysUserRole::getUserId, id);
        List<SysUserRole> sysUserRoles = sysUserRoleMapper.selectList(wrapper);
        if(CollectionUtils.isEmpty(sysUserRoles)){
            return new ArrayList<>();
        }
        List<SysRole> sysRoles = sysRoleMapper.selectBatchIds(sysUserRoles.stream().map(SysUserRole::getRoleId).collect(Collectors.toList()));
        List<SysRole> result = sysRoles.stream().filter(e -> e.getDel().equals(Boolean.FALSE)).collect(Collectors.toList());
        return result;
    }

    @Override
    @Transactional
    public void del(Integer id) {

        LambdaUpdateChainWrapper<SysRole> wrapper = new LambdaUpdateChainWrapper<>(sysRoleMapper);
        LocalDateTime now = LocalDateTime.now();
        boolean update = wrapper.eq(SysRole::getId, id)
                .set(SysRole::getDel, true)
                .set(SysRole::getDeleteTime, now)
                .set(SysRole::getUpdateTime, now)
                .update();

    }

    @Override
    public Page<SysRole> page(SysRoleDTO condition) {
        QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .likeRight(SysRole::getName, condition.getName())
                .eq(SysRole::getDel, false);

        Page<SysRole> pageCondition = new Page<>(condition.getPage(), condition.getSize());
        Page<SysRole> page = sysRoleMapper.selectPage(pageCondition, wrapper);
        if(page.getTotal() != 0){
            page.getRecords()
                    .forEach(e-> {
                        SysUser sysUser = sysUserMapper.selectById(e.getCreator());
                        e.setCreatorName(sysUser.getNickname());
                        QueryWrapper<SysRoleAuth> roleAuthQueryWrapper = new QueryWrapper<>();
                        roleAuthQueryWrapper.lambda()
                                .eq(SysRoleAuth::getRoleId, e.getId());
                        List<SysRoleAuth> sysRoleAuths = sysRoleAuthMapper.selectList(roleAuthQueryWrapper);
                        e.setPermissions(sysRoleAuths.stream().map(SysRoleAuth::getAuthId).collect(Collectors.toSet()));
                    });
        }
        return page;
    }
}
